﻿using DXBase;
using DXBase.D3D;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI;
using DXBase.Scenes;
using DXBase.Structs;

namespace DXBase.Samples
{
	public class Universe : D3DScene
	{
		public Universe()
		{
			Updating = true;

			UpdateActions = new List<Action<Universe, PerformanceTimer>>();
			Background = Colors.Azure;
			Bodies = new List<SpaceBody>();
			StartCamera = new Camera()
			{
				EyeLocation = new Vector3F(0, 0.0f, 0.0f),
				LookVector = new Vector3F(0, 0, 100),
				UpVector = new Vector3F(0, 1, 0),
				FarPlane = 800,
			};
			Reset();

			RasterizerState = new RasterizerState();
		}

		public CULL_MODE[] CullModes
		{
			get
			{
				return new[]
				{
					CULL_MODE.BACK,
					CULL_MODE.FRONT,
					CULL_MODE.NONE,
				};
			}
		}

		public string Name { get; set; }

		public bool Updating { get; set; }
		public List<Action<Universe, PerformanceTimer>> UpdateActions { get; private set; }

		public List<SpaceBody> Bodies { get; private set; }
		public IEnumerable<SpaceBody> GetBodies()
		{
			foreach (var item in Bodies)
				foreach (var subitem in item.GetSystem())
					yield return subitem;
		}

		public void Reset()
		{
			CameraController.Camera = this.Camera.Clone();
			CameraController.Reset();
		}

		public PixelShader PixelShader { get; set; }
		public VertexShader VertexShader { get; set; }
		public RasterizerState RasterizerState { get; set; }

		public override void Update(DXContext ctxt, PerformanceTimer ptimer)
		{
			base.Update(ctxt, ptimer);
			if (!Updating)
				return;

			foreach (var item in Bodies)
				item.Update(null, ptimer);
			foreach (var a in UpdateActions)
				a(this, ptimer);
		}

		public override void Render(D3DGraphic g)
		{
			g.Clear(Background);

			g.PixelShader = PixelShader;
			g.VertexShader = VertexShader;
			g.SetStateSampler(Sampler);
			g.SetStateRasterizer(RasterizerState);

			g.SetConstantBuffers(4, ShaderType.Pixel | ShaderType.Vertex, PerObjectData.Buffer);
			g.SetConstantBuffers(0, ShaderType.Pixel, PerFrameData.Buffer, DirLights.Buffer, PointLights.Buffer, SpotLights.Buffer);

			CameraController.Camera.SetProjection(g.Context);
			foreach (var item in GetBodies())
			{
				if (item.Shape == null)
					continue;

				PerObject = new PerObjectData
				{
					projection = CameraController.Camera.Projection,
					WorldModel = CameraController.Camera.View * CameraController.ModelTransform.Transform * item.FinalTransform.Transform,
					WorldModelNorm = CameraController.Camera.View * CameraController.ModelTransform.Transform * item.FinalTransform.NormalTransform,
					material = item.Material,
					DrawFlags = item.Texture != null ? DrawFlag.UseTexel : DrawFlag.UseVertexColor,
				};

				g.SetShaderResource(ShaderType.Pixel, item.Texture);

				g.Shape = item.Shape;
				g.DrawIndexed();
			}
		}
	}
}
